<!--包含关系的相关代码 后续可以摘要-->
<template>
  <div>
    <div class="annotation-main" id="annotation" v-show="isShow">
      <div class="entity">
        <el-form
          :inline="true"
          class="entity-search km-form m-l"
          @submit.native.prevent
        >
          <el-form-item>
            <el-input
              class="km-input"
              v-model="entitySearch"
              placeholder="标签搜索"
            ></el-input>
          </el-form-item>
          <el-form-item>
            <el-button
              type="primary"
              class="km-button"
              @click="$refs.ontologyMenu.filter(entitySearch)"
              >搜索</el-button
            >
          </el-form-item>
        </el-form>
        <el-tree
          :data="ontologyMenu"
          @node-click="handleNodeClick"
          default-expand-all
          :expand-on-click-node="false"
          :filter-node-method="filterOntology"
          ref="ontologyMenu"
          class="entity-tree"
          ><span class="entity-item" slot-scope="{ node }">
            <span>{{ node.label }}</span>
          </span></el-tree
        >
      </div>
      <div class="article" id="article">
        <div class="article-tool-bar">
          <div class="controlPanel">
            <span
              :class="[
                shape === item.val
                  ? 'contro-item active m-r'
                  : 'contro-item m-r',
              ]"
              v-for="(item, idx) in shapes"
              :key="idx"
              @click="handleShape(item.val)"
            >
              <i :class="'iconfont' + item.icon"></i>
            </span>
          </div>
          <div>
            <el-button
              @click="handleSave"
              :loading="saveLoading"
              class="km-button"
              size="small"
              ><i class="iconfont2 icon-baocun"></i>保存</el-button
            >
            <!-- <el-button
            v-if="type == 'annotation'"
            @click="handlePreAnnotation"
            class="km-button"
            size="small"
            ><i class="iconfont2 icon-biaoji"></i>预标注</el-button
          >
          <el-button
            v-if="type == 'proofread' && !isConfirmed"
            @click="handleConfirm"
            :loading="confirmLoading"
            class="km-button"
            size="small"
            ><i class="iconfont2 icon-queren"></i>确认</el-button
          > -->
            <el-button
              class="km-button"
              size="small"
              @click="() => (isFullscreen = !isFullscreen)"
            >
              <i
                class="iconfont2"
                :class="{
                  'icon-full-screen': !isFullscreen,
                  'icon-compress': isFullscreen,
                }"
              ></i>
              {{ isFullscreen ? "退出全屏" : "全屏显示" }}</el-button
            >
          </div>
        </div>
        <div>
          <div id="canvas-box" style="">
            <canvas
              id="label-canvas"
              style="display: block; width: 100%; height: 100%"
            ></canvas>
          </div>
          <canvas
            id="myCanvas"
            style="display: none; width: 0; height: 0"
            v-show="false"
          ></canvas>
        </div>
      </div>
      <div class="entity">
        <div class="title">
          <span><span class="blue"></span>已有实体</span>
          <el-button
            v-if="resultArr.length > 0"
            class="km-button"
            @click="showChangeFun"
            size="mini"
            ><i class="iconfont2 icon-queren"></i>实体关系</el-button
          >
        </div>
        <div v-if="resultArr.length > 0">
          <div v-for="(item, index) in resultArr" :key="index" class="imgWrap">
            <span class="spanWrap"
              >{{ item.propertyName
              }}<img :src="item.entityName" class="imgStyle"
            /></span>
            <el-link type="primary" @click="delFun(item, index)">删除</el-link>
          </div>
        </div>
        <div v-else>
          <el-empty description="未标注实体"></el-empty>
        </div>
      </div>
    </div>

    <Entity
      v-show="!isShow"
      ref="entityWrapRef"
      :resultArr="resultArr"
      :relationTree="relationTree"
      :relationListInDom="relationListInDom"
      :width="width"
      :height="height"
      @update="updateFun"
      @change="
        () => {
          isShow = true;
        }
      "
    />
  </div>
</template>
<script>
import { fabric } from "fabric";
import Entity from "./entity";
export default {
  name: "Annotation",
  components: { Entity },
  data: () => {
    return {
      width: 0,
      height: 0,
      isShow: true,
      saveLoading: false,
      preAnnotationLoading: false,
      confirmLoading: false,
      loading: false,
      editor: null,
      // 带有层级关系的实体名称列表
      ontologyMenu: [],
      // 不带层级关系的实体名称列表
      ontologyList: [],
      ontologyObj: {},
      // 搜索实体
      entitySearch: "",
      // 搜索关系
      relationSearch: "",

      relationList: null,
      relationListToShow: [],

      selectedCategoryId: null,

      // 当前选中的实体属性列表
      rightClickpropertyList: [],
      // 当前选中的实体类型
      currentEntityType: null,

      rightClickTarget: null,
      rightClickTargetType: null,
      labelClickTarget: null,
      isMarkingAttribute: false,
      markCanvas: null,
      isFullscreen: false,
      // 随鼠标的连线
      relationLine: {
        show: false,
        targetY: 0,
        targetX: 0,
        topOffset: 0,
        leftOffset: 0,
        pointerX: 0,
        pointerY: 0,
        width: 0,
        height: 0,
      },
      remarkMenuLeft: 0,
      remarkMenuTop: 0,
      propertyListLeft: 0,
      propertyListTop: 0,
      colorList: [
        "#ABC4FF",
        "#F7C378",
        "#4FDADC",
        "#EE8FC4",
        "#C6ABFF",
        "#BFC6D3",
        "#D7B9B5",
        "#E3BABA",
        "#84D79F",
        "#B5C5B1",
        "#56CAED",
        "#C4B8A3",
        "#86BFFF",
        "#FF976F",
        "#96D6E5",
        "#D1BBD1",
        "#8BCFF2",
        "#DAB37E",
        "#F3B0CD",
        "#FFBE84",
        "#FF8181",
        "#ABABDF",
        "#FA99AC",
        "#FFC2AD",

        "#A1BFCE",
        "#C3DD8B",
        "#D1ACE0",
        "#83CDFF",
        "#FEA1BF",
        "#78DBBF",
      ],

      loading: true,
      fabricObj: null,
      fabricJson: {},
      drawingObject: null, //绘制对象
      moveCount: 1,
      mouseFrom: {},
      mouseTo: {},
      doDrawing: false,
      activeIndex: 0,
      dialog: false,
      imgDialog: false,
      exportBaseData: "",
      ableEdit: false,
      page: 1,
      pageSize: 4,
      shape: "rectangle",
      shapes: [
        { val: "rectangle", icon: " icon-juxing" },
        { val: "circle", icon: " icon-yuanxing" },
        { val: "undo", icon: " icon-huitui" },
        { val: "redo", icon: " icon-xiangqian" },
        { val: "reset", icon: " icon-reset" },
      ],

      labelResult: {},
      dataURL: "",
      canvas: null,
      fabricBase64: null,
      radius: "",
      resultArr: [],
      fabricHistoryJson: [],
      mods: 0,
      relationListBack: [],
      relationTree: {},
      canvasWidth: "",
      canvasHeight: "",
    };
  },
  props: {
    type: {
      type: String,
      default: "annotation",
    },
    isConfirmed: {
      type: Boolean,
      default: false,
    },
    annotationSourceData: {
      type: Object,
      default: () => ({
        relationList: [],
        ontologyMenu: [],
        ontologyList: [],
        attributeList: [],
        content: "",
        record: {},
      }),
    },
  },
  computed: {},
  watch: {
    // 全屏显示切换
    isFullscreen(value) {
      value
        ? document.getElementById("annotation").requestFullscreen()
        : document.fullscreenElement && document.exitFullscreen();
    },
  },
  created() {},
  mounted() {
    this.width = document.getElementById("article").scrollWidth || 1480;
    this.height = document.getElementById("article").scrollHeight || 817;
  },
  computed: {
    relationListInDom() {
      return this.relationListToShow.filter((relation) => relation.isEnable);
    },
  },
  methods: {
    updateFun(val) {
      this.relationTree = val.dataGap;
      if (val.relationArr) {
        this.relationListBack.push(val.relationArr);
      }
    },
    init() {
      this.ontologyMenu = [...this.annotationSourceData.ontologyMenu];
      this.ontologyList = this.annotationSourceData.ontologyList.map(
        (ontology, index) => {
          return {
            ...ontology,
            color: this.colorList[index % this.colorList.length],
          };
        }
      );
      this.ontologyList.forEach((ontology) => {
        this.ontologyObj[ontology.value] = ontology;
      });
      const relationList = this.annotationSourceData.relationList.map(
        (relation) => {
          const headEntity = this.ontologyObj[relation.headId];
          const tailEntity = this.ontologyObj[relation.tailId];
          const relationShowName = `${headEntity?.label} - ${relation.relationName} - ${tailEntity?.label}`;
          return { ...relation, relationShowName };
        }
      );
      this.relationList = [...relationList];
      this.relationListToShow = [...relationList];
      this.attributeList = this.ontologyList
        .filter((item) => item.propertyList)
        .map((item) =>
          item.propertyList.map((property) => ({
            ...property,
            color: item.color + "E6",
          }))
        )
        .flat();
      this.relationTree = this.annotationSourceData?.record?.relationTree || {};
      this.relationListBack =
        this.annotationSourceData?.record?.relationList || [];
      // 过滤禁用的实体
      this.$nextTick(() => {
        this.$refs.ontologyMenu.filter("");
      });
      let url = this.annotationSourceData.content || "";
      this.getPic(url);
      return true;
    },
    resetAnnotationData(annotationData) {
      let _this = this;
      const { entityList } = annotationData;
      entityList.forEach((item) => {
        let val = "";
        let text = "";
        switch (item.type) {
          case "rectangle":
            val = new fabric.Path(item.data.path, {
              left: item.data.left,
              top: item.data.top,
              stroke: "red",
              strokeWidth: 2,
              fill: "rgba(255, 255, 255, 0)",
              selectable: false,
            });
            text = new fabric.Text(item.propertyName, {
              left: item.data.left,
              top: item.data.top - 16,
              fill: "#fff",
              backgroundColor: "red",
              fontSize: "14",
              selectable: false,
            });
            this.resultArr.push({
              type: item.type,
              propertyName: item.propertyName,
              entityTypeId: item.entityTypeId,
              entityName: item.entityName,
              entityId: item.entityId,
              data: {
                path: item.data.path,
                left: item.data.left,
                top: item.data.top,
              },
            });
            break;
          case "circle":
            val = new fabric.Circle({
              left: item.data.left,
              top: item.data.top,
              radius: item.data.radius,
              stroke: "red",
              fill: "rgba(255, 255, 255, 0)",
              strokeWidth: 2,
              selectable: false,
            });
            text = new fabric.Text(item.propertyName, {
              left: item.data.left + item.data.radius / 2,
              top: item.data.top - 16,
              fill: "#fff",
              backgroundColor: "red",
              fontSize: "14",
              selectable: false,
            });
            this.resultArr.push({
              type: item.type,
              propertyName: item.propertyName,
              entityTypeId: item.entityTypeId,
              entityId: item.entityId,
              entityName: item.entityName,
              data: {
                left: item.data.left,
                top: item.data.top,
                radius: item.data.radius,
              },
            });
            break;
          default:
            break;
        }
        _this.fabricObj.add(val);
        _this.fabricObj.add(text);
      });
    },

    handleNodeClick(data) {
      const entityType = this.ontologyObj[data.value];
      this.currentEntityType = {
        propertyId: data.value,
        propertyName: data.label,
        color: entityType.color,
      };
    },

    // 标注实体或属性
    markEntity(property) {
      console.log(
        "%c [  ]-570",
        "font-size:13px; background:pink; color:#bf2c9f;",
        property
      );
      // const windowSelection = window.getSelection();
      // const $selectionText = windowSelection.toString();
      // if (!$selectionText) {
      //   return;
      // }

      if (!property || !property.propertyName || !property.propertyId) {
        this.$message.warning("请先选中实体类别");
        return false;
      }
      return true;
      // const { anchorNode, anchorOffset, focusNode, focusOffset } =
      //   windowSelection;

      // const [startIndex, endIndex] =
      //   anchorOffset > focusOffset
      //     ? [focusOffset, anchorOffset]
      //     : [anchorOffset, focusOffset];

      // if (anchorNode.parentNode.classList.contains("ontology")) {
      //   this.$message.warning("当前选中文本无法被标注");
      //   console.log("嵌套标注");
      //   return;
      // }

      // if (anchorNode.parentNode.classList.contains("ontology-type")) {
      //   this.$message.warning("当前选中文本无法被标注");
      //   console.log("标注实体类别");
      //   return;
      // }

      // if (focusNode !== anchorNode) {
      //   this.$message.warning("当前选中文本无法被标注");
      //   console.log("跨节点");
      //   return false;
      // }

      // const uuid = guid();

      // const newDiv = document.createElement("span");

      // newDiv.innerHTML = `<span class="ontology" type="${type}" uuid="${uuid}">${$selectionText}</span>`;

      // const fragment = document.createDocumentFragment();
      // fragment.append(
      //   anchorNode.nodeValue.slice(0, startIndex),
      //   newDiv.firstElementChild,
      //   anchorNode.nodeValue.slice(endIndex)
      // );
      // anchorNode.parentNode.replaceChild(fragment, anchorNode);

      // const target = document.querySelector(`[uuid="${uuid}"]`);

      // if (!target) {
      //   this.$message.warning("当前选中文本无法标注");
      //   console.log("替换失败，未找到替换后的dom");
      //   return false;
      // }

      // target.style.setProperty("background-color", property.color, "important");
      // target.insertAdjacentHTML(
      //   "afterbegin",
      //   `<span
      //     class="ontology-type"
      //     id="${uuid}"
      //     otid="${property.propertyId}"
      //     >${property.propertyName}</span>`
      // );

      // // 标注之后重绘连线

      // this.markCanvas.initRelations();

      // return {
      //   id: uuid,
      //   property,
      // };
    },

    // 获取关系标注信息
    getMarkRelationInfo(startElement, endElement, relation) {
      const uperElement = this.getUperOne(startElement, endElement);
      let currentMarginTop = uperElement.parentNode.style.marginTop;

      if (currentMarginTop) {
        currentMarginTop = parseInt(currentMarginTop);
      }
      uperElement.parentNode.style.marginTop = currentMarginTop + 30 + "px";
      return {
        id: guid(),
        startElement: startElement.id,
        endElement: endElement.id,
        relation: relation.relationName,
        relationTypeId: relation.relationId,
        step: currentMarginTop + 20,
      };
    },
    // 标注关系方法
    markRelation(startElement, endElement, relation) {
      this.markCanvas.createRelation(
        this.getMarkRelationInfo(startElement, endElement, relation)
      );
    },
    getUperOne(element1, element2) {
      const { top: top1, left: left1 } = this.getElementOffset(element1);
      const { top: top2, left: left2 } = this.getElementOffset(element2);
      if (top1 !== top2) {
        return top1 < top2 ? element1 : element2;
      } else {
        return left1 < left2 ? element1 : element2;
      }
    },
    getElementOffset(el) {
      let top = 0;
      let left = 0;
      do {
        top += el.offsetTop;
        left += el.offsetLeft;
        el = el.offsetParent;
      } while (el);

      return { top, left };
    },
    // 展示标注随鼠标的连线
    showRelationLine(e) {
      let box = document.getElementById("wangEditor");

      const { top: targetY, left: targetX } = this.getElementOffset(e);
      const { top, left } = this.getElementOffset(
        document.getElementById("wangEditor")
      );

      // 起始点坐标
      this.relationLine.targetX = targetX - left;
      this.relationLine.targetY = targetY - top;

      // 画布大小
      this.relationLine.height = box.scrollHeight;
      this.relationLine.width = box.scrollWidth;

      // 终点初始坐标防止初始显示时连线漂移
      this.relationLine.pointerX = targetX - left;
      this.relationLine.pointerY = targetY - top;

      this.relationLine.leftOffset = left;
      this.relationLine.topOffset = top;

      // 展示连线
      this.relationLine.show = true;

      document.addEventListener("mousemove", this.followMouse);
    },
    // 鼠标移动更新连线终点
    followMouse(e) {
      this.relationLine.pointerX =
        e.pageX -
        this.relationLine.leftOffset +
        this.$refs?.annotationBox?.scrollLeft;
      this.relationLine.pointerY =
        e.pageY -
        this.relationLine.topOffset +
        this.$refs?.annotationBox?.scrollTop;
    },

    // 隐藏连线
    hideRelationLine() {
      this.relationLine.show = false;
      document.removeEventListener("mousemove", this.followMouse);
    },
    async handlePreAnnotation() {
      const entity = document.querySelector(`.ontology-type`);
      if (entity) {
        try {
          await this.$confirm(
            "是否确认进行预标注？预标注后将会覆盖当前已标注内容。",
            "预标注",
            {
              confirmButtonText: "确定",
              cancelButtonText: "取消",
              type: "warning",
              customClass: "pre-annotation-confirm",
            }
          );
        } catch (e) {
          console.log(e);
          return;
        }
      }
      this.$emit("preAnnotation", "", () => {
        this.preAnnotationLoading = false;
      });
    },

    // 保存标注数据
    handleSave() {
      this.saveLoading = true;
      // const relationList = this.getRelationList();
      const { entityList, attributeList } = this.getEntityList();
      // const article = this.getArticle();

      console.log(
        "%c [  ]-723",
        "font-size:13px; background:pink; color:#bf2c9f;",
        this.relationListBack
      );
      const params = {
        relationList: this.relationListBack,
        entityList: this.resultArr,
        attributeList,
        relationTree: this.relationTree,
        // article,
      };
      this.$emit("save", params, () => {
        this.saveLoading = false;
      });
    },

    // 确认抽取数据
    handleConfirm() {
      this.confirmLoading = true;
      const relationList = this.getRelationList();
      const { entityList, attributeList } = this.getEntityList();
      // const article = this.getArticle();
      const params = {
        relationList,
        entityList,
        attributeList,
        // article,
      };
      console.log(params);
      this.$emit("confirm", params, () => {
        this.confirmLoading = false;
      });
    },
    handleData(data) {
      data.forEach((item) => {
        if (item.children.length > 0) {
          let headEntityId = item.entityId;
          item.children.forEach((items) => {});
        }
      });
    },
    // 从关系标注数据中获取保存用的数据结构
    getRelationList() {
      let arr = [];
      this.relationListBack.children.forEach((item) => {
        if (item.children.length > 0) {
          let headEntityId = item.entityId;
        }
      });
      // const relationList = this.markCanvas.cacheElements.map((relation) => ({
      //   id: relation.id,
      //   headEntityId: relation.startElement,
      //   tailEntityId: relation.endElement,
      //   relationTypeId: relation.relationTypeId.toString(),
      // }));
      // return relationList;
    },
    // 从实体标注数据中获取保存用的数据结构 包含实体和属性
    getEntityList() {
      let entityList = [];
      let attributeList = [];
      document.querySelectorAll(".ontology-type").forEach((entityElement) => {
        // 属性实体
        if (entityElement.parentNode.attributes.type.value == "attribute") {
          // 具有id的属性实体
          if (entityElement.attributes.otid && entityElement.attributes.otid) {
            attributeList.push({
              attributeTypeId: entityElement.attributes.otid.value,
              attributeValue:
                entityElement.parentNode.childNodes[
                  entityElement.parentNode.childNodes.length - 1
                ].textContent,
              attributeId: entityElement.id,
            });
            // 没有id的属性实体 私有属性
          } else {
            attributeList.push({
              attributeType: entityElement.attributes.attributeType.value,
              attributeValue:
                entityElement.parentNode.childNodes[
                  entityElement.parentNode.childNodes.length - 1
                ].textContent,
              attributeId: entityElement.id,
            });
          }
          // 普通实体
        } else {
          entityList.push({
            entityTypeId: entityElement.attributes.otid.value,
            entityName:
              entityElement.parentNode.childNodes[
                entityElement.parentNode.childNodes.length - 1
              ].textContent,
            entityId: entityElement.id,
          });
        }
      });
      return { entityList, attributeList };
    },
    filterOntology(value, data) {
      if (!data.isEnable) {
        return false;
      }
      if (!value) {
        return true;
      }
      return data.label.indexOf(value) !== -1;
    },

    /**
     * @desc 初始化fabric，添加图待标注图片到画布中。
     * */
    fabricCanvas() {
      let canvasBox = document.getElementById("canvas-box");
      document.getElementById("label-canvas").width = this.canvasWidth;
      document.getElementById("label-canvas").height = this.canvasHeight;
      document.getElementById("myCanvas").width = this.canvasWidth;
      document.getElementById("myCanvas").height = this.canvasHeight;
      this.fabricObj = new fabric.Canvas("label-canvas");
      this.fabricObj.selectable = false;
      this.fabricObj.selection = false;
      this.fabricObj.skipTargetFind = true;
      this.canvas = new fabric.Canvas("myCanvas");
      this.canvas.selectable = false;
      this.canvas.selection = false;
      this.canvas.skipTargetFind = true;
      let url = this.annotationSourceData.content || "";
      this.getUrl(url, "fabric");
      this.getUrl(url, "canvas");

      canvasBox.style.height = this.canvasHeight + "px";
    },
    // 获取图片实际的宽度高度(保证图片不失真)
    getPic(url) {
      const _this = this;
      let img = new Image();
      img.src = "http://" + url;
      img.crossOrigin = "anonymous";
      img.onload = () => {
        _this.canvasWidth = img.width;
        _this.canvasHeight = img.height;
        // if (width / height > this.canvasWidth / this.canvasHeight) {
        //   this.scale = this.canvasWidth / width;
        // } else {
        //   this.scale = this.canvasHeight / height;
        // }
        _this.$nextTick(() => {
          setTimeout(() => {
            _this.loading = false;
            _this.fabricCanvas();
            _this.fabricObjEvent();
          }, 100);
        });
      };
    },
    getUrl(url, type, obj) {
      const _this = this;
      let img = new Image();
      img.src = "http://" + url;
      img.crossOrigin = "anonymous";

      img.onload = () => {
        let imgNew = new fabric.Image(img, {
          selectable: false,
          crossOrigin: "anonymous",
        });
        switch (type) {
          case "fabric":
            _this.fabricObj.add(imgNew);
            _this.fabricObj.renderAll();
            _this.canvas.renderAll();
            if (_this.annotationSourceData.record) {
              _this.resetAnnotationData(_this.annotationSourceData.record);
            }
            break;
          case "canvas":
            _this.canvas.add(imgNew);
            _this.canvas.renderAll();
            break;
          case "onlyFabric":
            _this.fabricObj.add(imgNew);
            _this.fabricObj.renderAll();
            break;
          case "clearAndCanvas":
            _this.fabricObj.add(imgNew);
            _this.fabricObj.renderAll();
            this.resultArr = [];
            this.resetAnnotationData(obj);
            break;

          default:
            break;
        }
      };
    },
    /**
     * @desc事件监听
     * */
    fabricObjEvent() {
      const _this = this;
      // this.fabricObj.isDrawingMode = true;
      this.fabricObj.on({
        "mouse:down": (e) => {
          if (!this.markEntity(this.currentEntityType)) {
            return;
          }
          if (this.ableEdit) {
            return;
          }
          this.doDrawing = true;
          // e.preventDefault();
          //鼠标按下
          console.log("mouse down");
          this.mouseFrom.x = e.pointer.x;
          this.mouseFrom.y = e.pointer.y;
          // this.doDrawing = true;
        },
        "mouse:move": (e) => {
          //鼠标移动
          if (this.moveCount % 2 && !this.doDrawing) {
            //减少绘制频率
            return;
          }
          this.moveCount++;
          this.mouseTo.x = e.pointer.x;
          this.mouseTo.y = e.pointer.y;
          this.drawing();
        },
        "mouse:up": (e) => {
          //鼠标抬起
          this.moveCount = 1;
          this.mouseTo.x = e.pointer.x;
          this.mouseTo.y = e.pointer.y;
          let fabricText = "";
          if (this.currentEntityType && this.currentEntityType.propertyName) {
            switch (this.shape) {
              case "rectangle":
                fabricText = new fabric.Text(
                  this.currentEntityType.propertyName,
                  {
                    left: this.mouseFrom.x,
                    top: this.mouseFrom.y - 16,
                    fill: "#fff",
                    backgroundColor: "red",
                    fontSize: "14",
                    selectable: false,
                  }
                );

                break;
              case "circle":
                fabricText = new fabric.Text(
                  this.currentEntityType.propertyName,
                  {
                    left: this.mouseFrom.x + this.radius / 2,
                    top: this.mouseFrom.y - 16,
                    fill: "#fff",
                    backgroundColor: "red",
                    fontSize: "14",
                    selectable: false,
                  }
                );
                break;
              default:
                break;
            }
            this.fabricObj.add(fabricText);
            this.canvas.add(_this.fabricBase64);
            this.canvas.clipTo = function (ctx) {
              _this.fabricBase64.render(ctx);
            };
            this.dataURL = this.canvas.toDataURL({
              format: "png",
              left: _this.fabricBase64.left,
              top: _this.fabricBase64.top,
              width: _this.fabricBase64.width,
              height: _this.fabricBase64.height,
            });
            let _objData = {};
            let url = this.annotationSourceData.content || "";
            this.getUrl(url, "canvas");
            switch (this.shape) {
              case "rectangle":
                _objData = {
                  type: this.shape,
                  propertyName: this.currentEntityType.propertyName,
                  entityTypeId: this.currentEntityType.propertyId,
                  entityId: guid(),
                  entityName: this.dataURL,
                  data: {
                    path: this.drawingObject.path,
                    left: this.drawingObject.left,
                    top: this.drawingObject.top,
                  },
                };

                this.resultArr.push(_objData);

                break;
              case "circle":
                _objData = {
                  type: this.shape,
                  propertyName: this.currentEntityType.propertyName,
                  entityTypeId: this.currentEntityType.propertyId,
                  entityId: guid(),
                  entityName: this.dataURL,
                  data: {
                    left: this.drawingObject.left,
                    top: this.drawingObject.top,
                    radius: this.drawingObject.radius,
                  },
                };
                this.resultArr.push(_objData);
                break;

              default:
                break;
            }
            this.$refs.entityWrapRef.addChildFun(_objData);
            this.updateModifications();
            this.drawingObject = null;
            if (!this.ableEdit) {
              this.manualLabel();
            }
          }

          this.doDrawing = false;
        },
        "object:moving": (e) => {
          //对象移动
          // console.log( 'object:moving')
          // console.log(e)
          // e.target.opacity = 0.5;
        },
        "object:added": (e) => {
          //增加对象
        },
        "object:modified": (e) => {
          //修改对象
          this.labelResult[this.activeIndex + ""][this.category].forEach(
            (item) => {
              if (item.id === e.target.id) {
                item = e.target;
                console.log(e.target);
                console.log(item);
              }
            }
          );
          console.log(this.labelResult);
        },
        "selection:created": (e) => {
          console.log("selection created");

          e.target.set({
            transparentCorners: false,
            cornerColor: "#ff7a55",
            cornerStrokeColor: "#ff7a55",
            borderColor: "red",
            cornerSize: 12,
            padding: 10,
            cornerStyle: "circle",
            borderDashArray: [3, 3],
          });
        },
      });
    },
    createEntity() {
      this.isShow = false;
      //  :resultArr="resultArr"
      // :relationListInDom="relationListInDom"
      // this.$refs.entityWrapRef?.init({
      //   resultArr: this.resultArr,
      //   relationListInDom: this.relationListInDom,
      // });
    },
    showChangeFun() {
      this.isShow = !this.isShow;
    },
    /**
     * @desc 点击图形开始画图
     * @param {String} shape 要绘制的形状
     * */
    handleShape(shape) {
      let state = this.fabricHistoryJson;
      this.shape = shape;
      switch (this.shape) {
        case "rectangle":
        case "circle":
          this.ableEdit = false;
          this.fabricObj.isDrawingMode = false;
          this.fabricObj.selectable = false;
          this.fabricObj.selection = false;
          this.fabricObj.skipTargetFind = true;
          break;
        case "undo":
          if (this.mods < state.length) {
            this.fabricObj.clear().renderAll();
            this.fabricObj.loadFromJSON(
              state[state.length - 1 - this.mods - 1]
            );
            this.fabricObj.renderAll();
            this.mods += 1;
            if (this.mods == 1) {
              let url = this.annotationSourceData.content || "";
              this.fabricObj.add(this.getUrl(url));
              this.fabricObj.renderAll();
            }
          }
          break;
        case "redo":
          if (this.mods > 0) {
            this.fabricObj.clear().renderAll();
            this.fabricObj.loadFromJSON(
              state[state.length - 1 - this.mods + 1]
            );
            this.fabricObj.renderAll();
            this.mods -= 1;
          }
          break;
        case "reset":
          this.fabricObj.clear();
          let url = this.annotationSourceData.content || "";
          this.getUrl(url, "onlyFabric");
          this.resultArr = [];
          break;
      }
    },
    updateModifications() {
      this.fabricHistoryJson.push(JSON.stringify(this.fabricObj));
    },
    drawing() {
      const _this = this;
      if (this.drawingObject) {
        this.fabricObj.remove(this.drawingObject);
      }
      let fabricNew = null;
      switch (this.shape) {
        case "polygons":
          //绘制多边形
          break;
        case "rectangle":
          //绘制矩形
          let path =
            "M " +
            this.mouseFrom.x +
            " " +
            this.mouseFrom.y +
            " L " +
            this.mouseTo.x +
            " " +
            this.mouseFrom.y +
            " L " +
            this.mouseTo.x +
            " " +
            this.mouseTo.y +
            " L " +
            this.mouseFrom.x +
            " " +
            this.mouseTo.y +
            " L " +
            this.mouseFrom.x +
            " " +
            this.mouseFrom.y +
            " z";
          fabricNew = new fabric.Path(path, {
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            stroke: "red",
            strokeWidth: 2,
            fill: "rgba(255, 255, 255, 0)",
            selectable: false,
          });

          // fabricText = new fabric.Text(this.currentEntityType.propertyName, {
          //   left: this.mouseFrom.x,
          //   top: this.mouseFrom.y - 16,
          //   fill: "red",
          //   fontSize: "14",
          //   selectable: false,
          // });
          _this.fabricBase64 = new fabric.Path(path, {
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            globalCompositeOperation: "destination-in",
          });
          break;
        case "trapezoid":
          //绘制梯形
          break;
        case "circle":
          //绘制圆形
          this.radius =
            Math.sqrt(
              (this.mouseTo.x - this.mouseFrom.x) *
                (this.mouseTo.x - this.mouseFrom.x) +
                (this.mouseTo.y - this.mouseFrom.y) *
                  (this.mouseTo.y - this.mouseFrom.y)
            ) / 2;
          fabricNew = new fabric.Circle({
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            stroke: "red",
            fill: "rgba(255, 255, 255, 0)",
            radius: this.radius,
            strokeWidth: 2,
          });
          _this.fabricBase64 = new fabric.Circle({
            left: this.mouseFrom.x,
            top: this.mouseFrom.y,
            radius: this.radius,
            globalCompositeOperation: "destination-in",
          });
          break;
      }
      if (fabricNew) {
        fabricNew.set("shape", this.shape);
        this.fabricObj.add(fabricNew);
        this.drawingObject = fabricNew;
      }
    },
    /**
     * @desc 编辑事件
     * */
    edit() {
      this.ableEdit = true;
      this.doDrawing = false;
      this.shape = "";
      this.fabricObj.isDrawingMode = false;
      this.fabricObj.selectable = true;
      this.fabricObj.selection = true;
      this.fabricObj.skipTargetFind = false;
    },
    delFun(item, index) {
      this.$confirm(
        "确认此实体吗？删除后对应的建议的实体关系也将一并删除，请谨慎操作。",
        "提示",
        {
          confirmButtonText: "确定",
          cancelButtonText: "取消",
          type: "warning",
        }
      )
        .then(() => {
          let _result = JSON.parse(JSON.stringify(this.resultArr));
          this.$refs.entityWrapRef.removeNode(item.entityId);
          this.changeRelation(item);
          if (this.resultArr.indexOf(item) > -1) {
            _result.splice(index, 1);
          }
          this.fabricObj.clear();
          let url = this.annotationSourceData.content || "";
          this.getUrl(url, "clearAndCanvas", {
            entityList: _result,
          });
        })
        .catch(() => {});
    },
    // 关系处理
    changeRelation(item) {
      let handleData = [];
      this.relationListBack.forEach((i) => {
        if (
          item.entityId != i.headEntityId &&
          item.entityId != i.tailEntityId
        ) {
          handleData.push(i);
        }
      });
      this.relationListBack = handleData;
    },
    /**
     * @desc 手动标注
     * */
    manualLabel() {
      // this.dialog = true;
    },
    /**
     * @desc 标注完后添加备注信息
     * @param flag {Boolean}   取消或确认
     * */
    sureLabel(flag) {
      let type, shape;
      this.categorylist.map((item) => {
        if (item.val === this.category) type = item.text;
      });
      this.shapes.map((item) => {
        if (item.val === this.shape) shape = item.text;
      });
      if (flag) {
      } else {
        let removeObj = this.labelResult[this.activeIndex][this.category].pop();
        this.fabricObj.remove(removeObj);
      }
      this.fabricJson[this.activeIndex] = JSON.stringify(this.fabricObj);
      this.dialog = false;
    },
    /**
     * @desc 编辑或删除当前图形
     * @param  {String} command 编辑或删除命令
     * @param  {Number} id 编辑或删除图形的id
     * @param  {String} category 当前类型
     * */
    handleCommand(command, id, category) {
      let currentFabric, currentIndex;
      this.labelResult[this.activeIndex][category].forEach((item, index) => {
        if (item.id === id) {
          currentFabric = item;
          currentIndex = index;
        }
      });
      if (command === "edit") {
        //编辑操作
        this.shape = "";
        this.ableEdit = true;
        this.fabricObj.selectable = true;
        this.fabricObj.selection = true;
        this.fabricObj.skipTargetFind = false;
        console.log(currentFabric);
        this.fabricObj.bringToFront(currentFabric);
        this.fabricObj.setActiveObject(currentFabric);
      } else if (command === "delete") {
        //删除操作
        this.fabricObj.remove(currentFabric);
        this.labelResult[this.activeIndex][category].splice(currentIndex, 1);
        this.$forceUpdate();
      }
    },
  },
};
function guid() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    let r = (Math.random() * 16) | 0,
      v = c == "x" ? r : (r & 0x3) | 0x8;

    return v.toString(16);
  });
}
</script>
<style lang="scss" scoped>
.annotation-main {
  display: flex;
  justify-content: space-between;
  height: calc(100vh - 120px);
  width: 100%;
  background-color: #fff;
  border-radius: 4px;
  &:fullscreen {
    height: 100%;
    padding: 30px;
  }
  .entity {
    // padding: 0 40px;
    flex-shrink: 0;
    margin: 0 auto;
    width: 280px;
    height: 100%;
    .entity-tree {
      height: calc(100% - 62px);
      overflow: auto;
      &::-webkit-scrollbar {
        display: none; /* Chrome Safari */
      }
      ::v-deep .el-tree-node {
        margin-top: 12px;
        .el-tree-node__content {
          height: auto;
        }
        &:focus > .el-tree-node__content {
          background-color: #fff;
        }
        &.is-current {
          > .el-tree-node__content {
            .entity-item {
              background: rgba(75, 113, 235, 0.12);
              border: 1px solid #4b71eb;
              color: #4b71eb;
            }
          }
        }
      }
      .entity-item {
        padding: 0 16px;
        height: 32px;
        border-radius: 2px;
        border: 1px solid #dddddd;
        line-height: 32px;
        font-size: 14px;
        color: #333333;
      }
      &.el-tree {
        ::v-deep .el-tree-node__expand-icon {
          font-family: "iconfont2" !important;
          font-size: 14px;
          font-style: normal;
          -webkit-font-smoothing: antialiased;
          -moz-osx-font-smoothing: grayscale;
        }
        ::v-deep .el-icon-caret-right:before {
          // 未展开
          content: "\e65b";
        }
        ::v-deep .expanded:before {
          content: "\e65a";
          // 展开
        }
        ::v-deep .expanded {
          // 展开不旋转
          -webkit-transform: rotate(0deg);
          transform: rotate(0deg);
        }
      }
    }
  }

  .article {
    flex-grow: 1;
    width: 100%;
    overflow: auto;
    border: 1px solid #dddddd;
    box-shadow: inset 0px 0px 0px 16px #f3f4f8;
    padding: 16px;
    border-radius: 4px;
    ::v-deep .w-e-text-container {
      background-color: rgba(0, 0, 0, 0);
    }
    .article-tool-bar {
      margin: 10px 20px;
      display: flex;
      justify-content: space-between;
      align-items: center;
      .km-button {
        border-color: $--color-primary;
        color: $--color-primary;
        .iconfont2 {
          font-size: 12px;
          margin-right: 8px;
        }
      }
    }
    > .article-annotation {
      height: calc(100% - 52px);
      overflow: overlay;

      &::-webkit-scrollbar-track-piece {
        background: #d3dce600;
      }

      &::-webkit-scrollbar {
        width: 6px;
        height: 6px;
      }

      &::-webkit-scrollbar-thumb {
        background: #b7bbc700;
        border-radius: 20px;
      }
      &:hover::-webkit-scrollbar-thumb {
        background: #b7bbc7;
      }
    }
    &::-webkit-scrollbar {
      display: none; /* Chrome Safari */
    }
  }
  .relationBlock {
    flex-shrink: 0;
    width: 280px;
    margin-left: 24px;
    .relation-tree {
      height: calc(100% - 62px);
      overflow: hidden auto;

      &::-webkit-scrollbar {
        display: none; /* Chrome Safari */
      }
      .relation-tree-list {
        display: flex;
        flex-direction: column;
      }
      .el-radio.is-bordered,
      .el-radio.is-bordered + .el-radio.is-bordered {
        margin: 10px 20px 0px 0px;
      }
    }
    .el-tag {
      margin: 10px;
    }
    overflow: auto;
  }

  .contextMenu {
    position: absolute;
    border: 1px solid steelblue;
    width: 100px;
    height: auto;
    padding: 3px;
    border-radius: 3px;
    background-color: #fff;
    z-index: 99999;
    li {
      list-style: none;
      width: 100%;
      height: 24px;
      line-height: 24px;
      font-size: 14px;
      display: inline-block;
      padding: 0;
      margin: 0 0 3px 0px;
      a {
        display: flex;
        align-items: center;
        justify-content: center;
        text-decoration: none;
        color: black;
        &:hover {
          background-color: rgba(77, 112, 190, 0.1);
          color: white;
        }

        &:active {
          background-color: rgba(77, 112, 190, 1);
        }
      }
    }
  }
  #relation-line {
    position: absolute;
  }

  ::v-deep .canvasBox {
    position: relative;
    display: inline-block;
    #wangEditor {
      width: 100%;
      height: 100%;
      color: #000;
      .multiple-ontology {
        display: inline-flex;
        flex-direction: column;
        vertical-align: bottom;
        border-radius: 2px;
        border: 1px solid #1e253d;
        padding: 0 3px 3px 3px;
        .ontology {
          margin-top: 3px;
        }
      }
      .ontology {
        display: inline-flex;
        flex-wrap: wrap;
        flex-direction: column;
        align-items: center;
        vertical-align: bottom;
        border-radius: 2px;
        text-indent: 0px;
        text-align: center;
        padding: 2px 2px 0 2px;
        // &[type="attribute"] {
        //   .ontology-type {
        //     background-color: #c2fcfc !important;
        //   }
        // }
        .ontology-type {
          border-radius: 2px;
          cursor: pointer;
          margin-bottom: 2px;
          padding: 3px;
          background-color: #fff !important;
          // font-size: 50%;
          width: 100%;
        }
      }
      div,
      p,
      span,
      strong {
        background-color: transparent !important;
      }
    }
    canvas {
      position: absolute;
      top: 0;
      left: 0;
    }
    .relationLabel {
      color: #000;
      background: #fff;
      z-index: 2;
      max-width: 100px;
      text-overflow: ellipsis;
      white-space: nowrap;
      overflow: hidden;
      border-radius: 5px;
      padding: 1px;
    }
  }
  .km-form.el-form {
    .el-form-item {
      margin-right: 0px;
      .km-input {
        width: 180px;
        height: 32px;
        background: #ffffff;
        line-height: 32px;
        ::v-deep .el-input__inner {
          border: 1px solid #dddddd;
          border-radius: 2px 0px 0px 2px;
          height: 32px;
          line-height: 32px;
        }
      }
      .km-button {
        border-radius: 0px 2px 2px 0px;
        width: 60px;
        height: 32px;
        padding: 0;
      }
      ::v-deep .el-form-item__content {
        line-height: 32px;
      }
    }
  }
}

.pre-text {
  padding-right: 5px;
}

.more-a {
  color: #0097dd;
  cursor: pointer;
  text-decoration: underline;
}

.img-box {
  border: 1px solid #dddeea;
  margin-bottom: 10px;
  cursor: pointer;
}

.img-box:hover {
  box-shadow: 0 0 5px 5px #ccc;
}

.img-box-active {
  border-color: #0097dd;
}

.controlPanel {
  // width: 100%;
  // height: 62px;
  // background: #ddd;
  // display: flex;
  // justify-content: center;
  // align-items: center;
  // /*margin-bottom: 15px;*/
  // border-bottom: 1px solid #dad7d9;
}
.blue {
  display: inline-block;
  width: 5px;
  height: 18px;
  background-color: #4b71eb;
  position: relative;
  margin-right: 15px;
  top: 3px;
}
.controlPanel .contro-item {
  flex-basis: 100px;
  // border: 1px solid #4b71eb;
  text-align: center;
  cursor: pointer;
  background: #fefefe;
  border-radius: 5px;
  color: #333;
  // font-size: 60px;
}

.contro-item.active {
  // background: #4b71eb;
  color: #4b71eb;
  // padding: 10px 20px;
  // border-radius: 5px;
}

.wraper .controlPanel .contro-item i {
  font-size: 60px;
  line-height: 62px;
  color: #333;
}
.wraper .controlPanel .contro-item.active i {
  color: #4b71eb;
  border-radius: 3px;
  font-size: 60px;
}

#canvas-box {
  border: 1px solid #dddeea;
  position: relative;
  // height: 100%;
  // width: 100%;
  overflow: auto;
  /*margin: 0 20px;*/
}

.result-tittle {
  border-left: 4px solid #409eff;
  padding-left: 10px;
  border-bottom: 1px solid #dddeea;
}

.result-content {
  padding: 10px;
}

.result-item {
  margin-bottom: 10px;
}

.result-sub-box {
  padding-left: 10px;
  display: flex;
  justify-content: space-between;
}

.result-sub-box:hover {
  color: #409eff;
}
.m-r {
  margin-right: 20px;
}
.m-l {
  margin-left: 20px;
}
.iconfont {
  font-size: 25px;
  font-weight: bolder;
}
.title {
  font-size: 18px;
  margin-left: 20px;
  margin-bottom: 20px;
  display: flex;
  justify-content: space-between;
  .km-button {
    border-color: $--color-primary;
    color: $--color-primary;
    .iconfont2 {
      font-size: 12px;
      margin-right: 8px;
    }
  }
}

.wrapDiv {
  display: flex;
  align-items: center;
  padding: 0 20px;
  margin-bottom: 20px;
  border: 1px solid #4b71eb;
  border-radius: 5px;
  margin: 10px 20px;
  cursor: pointer;
  .imgStyle {
    width: 50px;
    height: 50px;
    margin-left: 20px;
  }
}
.imgWrap {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 15px;
  padding: 0 20px;
  border: 1px solid #c7c4c4;
  margin-left: 20px;
  cursor: pointer;
}
.spanWrap {
  display: flex;
  align-items: center;
}
.imgWrap:hover {
  background-color: #e2e0e0;
  color: #fff;
}
.imgStyle {
  width: 30px;
  height: 30px;
  margin-left: 20px;
}
</style>
